package com.mxchip.livestarmobile.mobile.ui.call


import android.annotation.SuppressLint
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.Observer
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs
import com.trello.lifecycle2.android.lifecycle.AndroidLifecycle
import com.trello.rxlifecycle3.LifecycleProvider
import com.mxchip.livestarmobile.R
import com.mxchip.livestarmobile.mobile.constant.RxConstant
import com.mxchip.livestarmobile.mobile.repository.RoomClientRepository
import com.mxchip.livestarmobile.mobile.state.SystemData
import com.mxchip.livestarmobile.mobile.ui.Call
import com.mxchip.livestarmobile.mobile.ui.GroupCall
import com.mxchip.livestarmobile.mobile.ui.P2PMultiCall
import com.mxchip.livestarmobile.mobile.ui.P2PSingleCall
import com.mxchip.livestarmobile.mobile.util.Log.FileLog
import com.mxchip.livestarmobile.mobile.util.RingtoneManagement.LocalRingManagement
import com.mxchip.livestarmobile.mobile.util.RxBus.RxBus
import com.mxchip.livestarmobile.mobile.util.RxBus.RxSchedulersHelper
import com.videohigh.hxb.roomclient.action.MakeCallResp
import com.videohigh.hxb.roomclient.event.EnterEvent
import com.videohigh.hxb.roomclient.event.HangupEvent
import com.mxchip.livestarmobile.mobile.base.toast
import com.mxchip.livestarmobile.mobile.util.Log.MyLog
import com.videohigh.hxb.roomclient.action.SyncChannelResp
import io.reactivex.Observable
import io.reactivex.disposables.CompositeDisposable
import kotlinx.android.synthetic.main.fragment_green.*
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import java.text.SimpleDateFormat
import java.util.Locale
import java.util.Date
import java.util.concurrent.TimeUnit

class GreenFragment : Fragment() {

    private val provider: LifecycleProvider<Lifecycle.Event> = AndroidLifecycle.createLifecycleProvider(this)

    private val dbyViewModel by activityViewModels<DbyViewModel>()
    private val roomViewModel by activityViewModels<RoomViewModel>()
    private val screenViewModel by activityViewModels<ScreenViewModel>()

    private val args: GreenFragmentArgs by navArgs()

    private lateinit var call: Call
    private var fromTermNumber: String? = null

    private val termIds = arrayListOf<String>()
    private var groupId: String? = null
    private val logger = FileLog.getLogger(GreenFragment::class.java)
    private val compositeDisposable = CompositeDisposable()

    private lateinit var makeCallRespObservable: Observable<MakeCallResp>
    private lateinit var enterEventObservable: Observable<EnterEvent>
    private lateinit var hangupEventObservable: Observable<HangupEvent>
    private lateinit var disconnectEventObservable: Observable<Boolean>
    private lateinit var reconnectEventObservable: Observable<Boolean>

    override fun onDestroyView() {
        super.onDestroyView()
    }

    @SuppressLint("CheckResult")
    override fun onResume() {
        super.onResume()
        Observable.interval(30, 1, TimeUnit.SECONDS)
                .compose(provider.bindToLifecycle())
                .take(1)
                .compose(RxSchedulersHelper.io_main())
                .subscribe {
                    Log.d("GreenFragment", "AutoHangup-----30s hangup ${SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA).format(Date())}")
                    reqHangup()
                }
    }

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                              savedInstanceState: Bundle?): View? {

        return inflater.inflate(R.layout.fragment_green, container, false)
    }

    @SuppressLint("CheckResult")
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        Log.d("GreenFragment", "Recall-----onViewCreated ")
        this.call = args.call

        when (val call = this.call) {
            is GroupCall -> {
                this.roomViewModel.setGroupId(call.groupNumber)

                head_portrait.setImageResource(R.drawable.if_icon_user)
                user_name.text = ""
                phone_state.text = "正在进入会议..."
            }
            is P2PSingleCall -> {
                this.termIds.add(call.number)

                head_portrait.setImageResource(R.drawable.if_icon_user)
                user_name.text = call.number.trimStart('0')
                phone_state.text = getString(R.string.waiting_for_answer)
            }
            is P2PMultiCall -> {
                this.termIds.addAll(call.inviteNumbers)

                head_portrait.setImageResource(R.drawable.if_icon_group_filled)
                user_name.text = getString(R.string.initiating_multi_person_meeting)
                phone_state.text = getString(R.string.other_participants) + call.inviteNumbers.joinToString(",") { it.trimStart('0') }
            }
            else -> {
                Log.e("GreenFragment", "call pojo is not right")
            }
        }

        Log.e("GreenFragment", "termIds: $termIds")

        button_hangup.setOnClickListener {
            logger.info(SimpleDateFormat("yyyy-MM-dd-HH:mm:ss", Locale.CHINA).format(Date()) + " button_hangup.setOnClickListener")
            reqHangup()
        }

        lifecycleScope.launch {
            delay(30 * 1000)
            logger.info("${SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA).format(Date())} AutoHangup-----30s hangup ")
            reqHangup()
        }

        //发起邀请
        makeCallRespObservable = RxBus.get().register(RxConstant.MAKE_CALL_RESP, MakeCallResp::class.java)
        makeCallRespObservable.compose(provider.bindToLifecycle()).compose(RxSchedulersHelper.io_main())
                .subscribe(::respMakeCall) { error -> error.printStackTrace() }

        //主叫收到被叫的 接听/挂断 消息
        enterEventObservable = RxBus.get().register(RxConstant.ENTER_EVENT, EnterEvent::class.java)
        enterEventObservable.compose(provider.bindToLifecycle()).compose(RxSchedulersHelper.io_main())
                .subscribe(::onEnter) { error -> error.printStackTrace() }

        // 收到其他端挂断消息
        hangupEventObservable = RxBus.get().register(RxConstant.HANGUP_EVENT, HangupEvent::class.java)
        hangupEventObservable.compose(provider.bindToLifecycle()).compose(RxSchedulersHelper.io_main())
                .subscribe(::onHangup) { error -> error.printStackTrace() }

        disconnectEventObservable = RxBus.get().register(RxConstant.DISCONNECT, Boolean::class.java)
        disconnectEventObservable./*compose(provider.bindToLifecycle()).*/compose(RxSchedulersHelper.io_main())
                .subscribe(::onDisconnect) { error -> error.printStackTrace() }

        reconnectEventObservable = RxBus.get().register(RxConstant.RECONNECT, Boolean::class.java)
        reconnectEventObservable./*compose(provider.bindToLifecycle()).*/compose(RxSchedulersHelper.io_main())
                .subscribe(::onReConnect) { error -> error.printStackTrace() }


        reqInvite(termIds.toTypedArray(), roomViewModel.groupId.value)

        startPlayLocalRing()

        roomViewModel.isMyselfTheOnlyOneLeft.observe(viewLifecycleOwner, Observer {

            if(it == false) {
                return@Observer
            }

            lifecycleScope.launch {
                toast("对方已挂断")
                delay(1000)
                logger.info("${SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA).format(Date())} AutoHangup----- isMyselfTheOnlyOneLeft ")
                reqHangup()
            }
        })
    }

    override fun onDestroy() {
        super.onDestroy()
        stopPlayLocalRing()
        RxBus.get().unregister(RxConstant.MAKE_CALL_RESP, makeCallRespObservable)
        RxBus.get().unregister(RxConstant.ENTER_EVENT, enterEventObservable)
        RxBus.get().unregister(RxConstant.HANGUP_EVENT, hangupEventObservable)
        RxBus.get().unregister(RxConstant.DISCONNECT, disconnectEventObservable)
        RxBus.get().unregister(RxConstant.RECONNECT, reconnectEventObservable)


        compositeDisposable.clear()
    }

    private fun startPlayLocalRing() {
        compositeDisposable.add(Observable.interval(0, 0, TimeUnit.MILLISECONDS)
                .compose(RxSchedulersHelper.io())
                .take(1)
                .subscribe { aLong: Long? -> LocalRingManagement.getInstance().playMusic(R.raw.called,context) })
    }

    private fun stopPlayLocalRing() {
        if (LocalRingManagement.getInstance().isPlaying) {
            LocalRingManagement.getInstance().stop()
        }
    }

    private fun reqHangup() {
        Log.e("GreenFragment", "Appli.getServerState(): ")

        val roomId = roomViewModel.roomId.value
        val channelId = roomViewModel.channelId.value
        val callIndex = roomViewModel.callIndex.value



        Log.e("GreenFragment", "Appli.getServerState(): $roomId $channelId $callIndex")

        stopPlayLocalRing()



        if(!roomId.isNullOrBlank() && !channelId.isNullOrBlank() && !callIndex.isNullOrBlank()) {
            RoomClientRepository.hangup(roomId, channelId, callIndex)
        }
        dbyViewModel.join(null)
    }


    //发起邀请
    private fun reqInvite(termIds: Array<String>, groupId: String?) {
        RoomClientRepository.makeCall(groupId, termIds)
    }

    private fun respMakeCall(response: MakeCallResp) {

        Log.e("GreenFragment", "respMakeCall: $response")

        if(response.result == 1) {
            toast("呼叫异常")
            return
        }

        val roomId = response.callContext.roomId
        val channelId = response.callContext.channelId
        val callIndex = response.callContext.callIndex

        val callId = "${roomId}:${channelId}:${callIndex}"
        val termNumber  = "${response.from.roomId}T${response.from.termId}"
        fromTermNumber = termNumber

        roomViewModel.setRoomId(response.callContext.roomId)
        roomViewModel.setChannelId(response.callContext.channelId)
        roomViewModel.setCallIndex(response.callContext.callIndex)


        roomViewModel.onJoinRoom(termNumber)


        if (this.call is GroupCall) {

            dbyViewModel.join(callId)

            lifecycleScope.launch {
                delay(3000)
                if (dbyViewModel.join().value.isNullOrEmpty()) return@launch
                // SystemData.getInstance().currentState = State.BUSY


                RoomClientRepository.enterChannel(0, roomId, channelId, callIndex) { resp ->

                    if (resp.result != 0) {
                        lifecycleScope.launch {
                            toast("错误代码: ${resp.errorcode}" )
                        }
                        return@enterChannel
                    }

                    lifecycleScope.launch {

                        roomViewModel.onStartCallRoom(termNumber)
                        dbyViewModel.enterAfterJoined()
                        screenViewModel.enterAfterJoined()

                        // roomViewModel.onStartCallRoom("${SystemData.roomId}T${SystemData.userId}")

                        resp.terms.filter {
                            !(it.roomId == SystemData.roomId() && it.termId == SystemData.userId())
                        }.forEach {
                            val fromTermNumber = "${it.roomId}T${it.termId}"
                            roomViewModel.onStartCallRoom(fromTermNumber)
                            it.deviceNames?.forEach {
                                deviceName ->
                                roomViewModel.addAVDevice(AVDevice(fromTermNumber, deviceName))
                            }
                        }

                        val action = GreenFragmentDirections.actionGreenFragmentToCallControlFragment()
                        // action.termIds = termIds.toTypedArray() //greenViewModel.termIds.value?.toTypedArray()
                        findNavController().navigate(action)
                    }
                }


            }
        } else {

            val invitationResults = response.invitationResults

            val allInvitationsBusy = invitationResults.map{  it.code != "ok" }.reduce{ acc, b ->  acc && b }

            if(allInvitationsBusy) {
                toast("对方正忙，请稍后再呼叫")

                lifecycleScope.launch {
                    delay(3000)
                    reqHangup()
                }

            } else {
                invitationResults.forEach {
                    if(it.code == "ok") {
                        roomViewModel.onJoinRoom("${it.roomId}T${it.termId}")
                    }
                }
                dbyViewModel.join(callId)
            }

        }
    }


    private fun onEnter(event: EnterEvent) {
        Log.e("GreenFragment", "onEnter: $event")
        val termNumber  = "${event.from.roomId}T${event.from.termId}"


        val roomId = roomViewModel.roomId.value!!
        val channelId = roomViewModel.channelId.value!!
        val callIndex = roomViewModel.callIndex.value!!


        val sessionsJoin = roomViewModel.sessionsJoin.value
        if (!sessionsJoin.isNullOrEmpty() && sessionsJoin.contains(termNumber)) {

            roomViewModel.onStartCallRoom(termNumber)

            stopPlayLocalRing()

            enterChannel(roomId, channelId, callIndex)
        }
    }

    private fun enterChannel(roomId: String, channelId: String, callIndex: String) {
        RoomClientRepository.enterChannel(0, roomId, channelId, callIndex) { resp ->

            if (resp.result != 0) {
                lifecycleScope.launch {
                    toast("错误代码: ${resp.errorcode}")
                }
                return@enterChannel
            }

            lifecycleScope.launch {
                if (!fromTermNumber.isNullOrBlank()) {
                    roomViewModel.onStartCallRoom(fromTermNumber!!)
                }

                // roomViewModel.onStartCallRoom("${SystemData.roomId}T${SystemData.userId}")
                resp.terms.filter {
                    !(it.roomId == SystemData.roomId() && it.termId == SystemData.userId())
                }.forEach {
                    val fromTermNumber = "${it.roomId}T${it.termId}"
                    roomViewModel.onStartCallRoom(fromTermNumber)
                    it.deviceNames?.forEach { deviceName ->
                        roomViewModel.addAVDevice(AVDevice(fromTermNumber, deviceName))
                    }
                }

                dbyViewModel.enterAfterJoined()
                screenViewModel.enterAfterJoined()

                val action = GreenFragmentDirections.actionGreenFragmentToCallControlFragment()
                findNavController().navigate(action)
            }
        }
    }



    private fun onHangup(event: HangupEvent) {
        Log.e("GreenFragment", "onHangup: $event ${roomViewModel.sessionsAll.value}")
        val termNumber  = "${event.from.roomId}T${event.from.termId}"
        roomViewModel.onLeaveRoom(termNumber)
    }

    private fun onReConnect(v: Boolean) {
        lifecycleScope.launch {
            val roomId = roomViewModel.roomId.value
            val channelId = roomViewModel.channelId.value
            val callIndex = roomViewModel.callIndex.value
            if (roomId.isNullOrBlank() || channelId.isNullOrBlank() || callIndex.isNullOrBlank()) {
                logger.info(SimpleDateFormat("yyyy-MM-dd-HH:mm:ss", Locale.CHINA).format(Date())
                        + " onReConnect roomId:$roomId  channelId:$channelId  callIndex:$callIndex reqHangup")
                reqHangup()
                return@launch
            }
            while (!RoomClientRepository.connected()) {
                delay(1)
            }
            RoomClientRepository.syncChannel(roomId, channelId, callIndex) { syncChannelResp: SyncChannelResp? ->
                MyLog.logD(MyLog.SIGNALLING_MODEL,"GreenFragment: onReConnect: syncChannelResp ----- $syncChannelResp")
                if (syncChannelResp?.terms?.isNotEmpty() == true) {
                    enterChannel(roomId, channelId, callIndex)
                }
            }
        }

    }

    private fun onDisconnect(v: Boolean) {
        toast("当前网络差，正在尝试重连...")
    }

}
